#include "openmove_Prefix.h"
#include "SceneBase.h"
#include "OgreEngine.h"
#include "ExampleFrameListener.h"
#include "SkeletalAnimationFrameListener.h"
#include "OgreExternalTextureSourceManager.h"
#include "OgreExternalTextureSource.h"
#include "SceneBlanche.h"
#include "SimpleFrameListener.h"

#define PARTICLE_WIDTH_MAX 5.3f
#define PARTICLE_HEIGHT_MAX 38.7f

CSceneBlanche :: CSceneBlanche(COgreEngine &Creator, const String & Name, const int pos) : CSceneBase(Creator, Name, pos), m_MaxPluie(1500.0f), m_ParticleWidth(0.5f), m_ParticleHeight(16.0f), m_curPluie(0)
{
}

CSceneBlanche :: ~CSceneBlanche(void)
{
}

void CSceneBlanche :: Create(TCreatorEntities const &CreatorEntities, TCreatorNodes const &CreatorNodes, TCreatorLights const &CreatorLights, ENetConfig IsClient, Vector3 &CameraStartPos)
{
	CSceneBase::Create(CreatorEntities, CreatorNodes, CreatorLights, IsClient, CameraStartPos);


	ParticleSystem * system;
	SceneNode *node;
	system = m_OgreEngine.m_pCurrentSceneManager->createParticleSystem("CSceneBlanchePluie1", "pluieBlanche");
	node = m_pSceneNode->createChildSceneNode("CSceneBlanchePluie1", Vector3(-200.0f, -100.0f, -50.0f));
	node->attachObject(system);

	system = m_OgreEngine.m_pCurrentSceneManager->createParticleSystem("CSceneBlanchePluie2", "pluieBlanche");
	node = m_pSceneNode->createChildSceneNode("CSceneBlanchePluie2", Vector3(-200.0f, -100.0f, -50.0f));
	node->setDirection(-0.1, 0, 0);
	node->attachObject(system);

	system = m_OgreEngine.m_pCurrentSceneManager->createParticleSystem("CSceneBlanchePluie3", "pluieBlanche");
	node = m_pSceneNode->createChildSceneNode("CSceneBlanchePluie3", Vector3(-200.0f, -100.0f, -50.0f));
	node->setDirection(0.1, 0, 0);
	node->attachObject(system);
	//m_Compositors.push_back("B&W");

	/*
	SProjectorFrustum MainFrustum = CreateProjector("BlancheProjectorNode", Vector3(-89.3, 397.4, -1416.8), Quaternion(Degree(-23.752), Vector3::UNIT_Y));
	MainFrustum.m_Decal->setFOVy(Radian(Math::PI/1.01));

	MaterialPtr mat = (MaterialPtr)MaterialManager::getSingleton().getByName("blanche_cylindre/lambert3");
	Pass *pass = mat->getTechnique(0)->getPass(0);
	TextureUnitState *texState = pass->createTextureUnitState("Texte3.tga");
	texState->setProjectiveTexturing(true, MainFrustum.m_Decal);
	texState->setTextureAddressingMode(TextureUnitState::TAM_MIRROR);
	texState->setTextureFiltering(TFO_ANISOTROPIC);
	texState->setColourOperationEx(LBX_MODULATE_X2);
	texState->setTextureBorderColour(ColourValue(0.0f, 0.0f, 0.0f, 0.0f));
	*/
}

void CSceneBlanche :: Attach(void)
{
	CSceneBase::Attach();
	//m_pCurrentCamera->setPosition(-500.0f, 80.0f, 170.0f);
	//Quaternion Quat(Radian(Degree(-60.0f)), Vector3(0, 1, 0));
	//m_pCurrentCamera->setOrientation(Quat);
	//m_pCurrentCamera->setDirection(0, 0, -1);
	//m_OgreEngine.m_pViewPort->setBackgroundColour(ColourValue(1.0f, 1.0f, 1.0f, 1.0f));
	//m_OgreEngine.m_pCurrentSceneManager->setSkyBox(true, "SkyBox/Souffle");

	/*
	MaterialPtr mat = MaterialManager::getSingleton().getByName("ana-table/corpsANA_derana_test2_ana_peau_damoiselle_Standard");
	GpuProgramParametersSharedPtr params = mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
	params->setConstant(6, Vector4::ZERO);
	*/
	m_EndPoint = 1.0f;
	m_ParticleWidth = 0.5f;
	m_ParticleHeight = 16.0f;
	m_curPluie = 0.0f;
}

bool CSceneBlanche :: frameStarted(const FrameEvent& evt)
{
	CSceneBase::frameStarted(evt);

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_Z) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_BE_SetLight, 0, String("1.0"));
		m_pCameraFrameListener->mTimeUntilNextToggle = 0.2f;
	} 
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_X) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_BE_SetLight, 0, String("0.01"));
		m_pCameraFrameListener->mTimeUntilNextToggle = 0.2f;
	} 

	Light *light = findLight(String("BlancheLight1"));
	if (NULL != light && 0)
	{
		ColourValue col = light->getDiffuseColour();
		ColourValue val(m_EndPoint, m_EndPoint, m_EndPoint);
		val = col + (val - col) / 30.0f;
		light->setDiffuseColour(val);
		m_OgreEngine.m_pViewPort->setBackgroundColour(val);

		m_OgreEngine.setDebugText("LightDiffuse: " + StringConverter::toString(light->getDiffuseColour()));
		m_OgreEngine.setDebugText("ToColor: " + StringConverter::toString(val));
	}


	ParticleSystem * system;

	{
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie1");
		system->getEmitter(0)->setEmissionRate(m_curPluie);
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie2");
		system->getEmitter(0)->setEmissionRate(m_curPluie);
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie3");
		system->getEmitter(0)->setEmissionRate(m_curPluie);
	}

	/*
	if (m_Timer.getSeconds() < 30.0f)
	{
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie1");
		system->getEmitter(0)->setEmissionRate(m_Timer.getSeconds() * 10.0f);
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie2");
		system->getEmitter(0)->setEmissionRate(m_Timer.getSeconds() * 10.0f);
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie3");
		system->getEmitter(0)->setEmissionRate(m_Timer.getSeconds() * 10.0f);
	}

	if (m_Timer.getSeconds() > 30.0f)
	{
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie1");
		system->getEmitter(0)->setEmissionRate(std::min(100 * (m_Timer.getSeconds() - 30.0f), m_MaxPluie));
		m_OgreEngine.setDebugText("CSceneBlanchePluie1: " + StringConverter::toString(system->getEmitter(0)->getEmissionRate()));
	}
	if (m_Timer.getSeconds() > 40.0f)
	{
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie2");
		system->getEmitter(0)->setEmissionRate(std::min(100 * (m_Timer.getSeconds() - 40.0f), m_MaxPluie));

		m_OgreEngine.setDebugText("CSceneBlanchePluie2: " + StringConverter::toString(system->getEmitter(0)->getEmissionRate()));
	}
	if (m_Timer.getSeconds() > 45.0f)
	{
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie3");
		system->getEmitter(0)->setEmissionRate(std::min(100 * (m_Timer.getSeconds() - 45.0f), m_MaxPluie));
		m_OgreEngine.setDebugText("CSceneBlanchePluie3: " + StringConverter::toString(system->getEmitter(0)->getEmissionRate()));
	}
	if (m_Timer.getSeconds() > 50.0f)
	{
		if (0)
		{
		Real duration = 50.0f;
		for (size_t i = 1; i <= 3; ++i)
		{
			system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie" + StringConverter::toString(i));

			//width = StringConverter::parseReal(system->getParameter("particle_width"));
			m_ParticleWidth = 0.5f + ((PARTICLE_WIDTH_MAX - 0.5f) / duration) * (m_Timer.getSeconds() - 50.0f);

			//height = StringConverter::parseReal(system->getParameter("particle_height"));
			m_ParticleHeight = 16.0f + ((PARTICLE_HEIGHT_MAX - 16.0f) / duration) * (m_Timer.getSeconds() - 50.0f);
			system->setParameter("particle_height", StringConverter::toString(m_ParticleHeight));
		}
		}
		else
		{
		}
	}
	*/

	for (size_t i = 1; i <= 3; ++i)
	{
		system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie" + StringConverter::toString(i));
		system->setParameter("particle_width", StringConverter::toString(m_ParticleWidth));
		system->setParameter("particle_height", StringConverter::toString(m_ParticleHeight));
	}

	m_OgreEngine.setDebugText("particle_width: " + StringConverter::toString(m_ParticleWidth) + " - particle_height: " + StringConverter::toString(m_ParticleHeight));

	Real const fadeStart = 100.0f;
	if (m_Timer.getSeconds() > fadeStart)
	{
		Real duration = 10.0f;
		for (unsigned short i = 1; i <= 3; ++i)
		{
			system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie" + StringConverter::toString(i));
			Real pluie = m_MaxPluie - ((m_MaxPluie / duration) * (m_Timer.getSeconds() - fadeStart));
			system->getEmitter(0)->setEmissionRate(std::max(pluie, 0.0f));
		}

		ColourValue backColor = ColourValue::White - ((ColourValue::White / duration) * (m_Timer.getSeconds() - fadeStart));
		if ((m_Timer.getSeconds() - fadeStart) < duration)
		{
			m_OgreEngine.m_pViewPort->setBackgroundColour(backColor);
		}
		else
		{
			m_OgreEngine.m_pViewPort->setBackgroundColour(ColourValue::Black);
		}
	}

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_C))
	{
		m_MaxPluie = std::min(m_MaxPluie + 1, 100000.0f);
	} 
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_V))
	{
		m_MaxPluie = std::max(m_MaxPluie - 1, 0.0f);
	}

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_G))
	{
		for (size_t i = 1; i <= 3; ++i)
		{
			system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie" + StringConverter::toString(i));
			Real width = StringConverter::parseReal(system->getParameter("particle_width"));
			system->setParameter("particle_width", StringConverter::toString(width + 0.1f));
		}
	} 

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_H))
	{
		for (size_t i = 1; i <= 3; ++i)
		{
			system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie" + StringConverter::toString(i));
			Real height = StringConverter::parseReal(system->getParameter("particle_height"));
			system->setParameter("particle_height", StringConverter::toString(height + 0.1f));
		}
	} 

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_B))
	{
		for (size_t i = 1; i <= 3; ++i)
		{
			system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie" + StringConverter::toString(i));
			Real width = StringConverter::parseReal(system->getParameter("particle_width"));
			system->setParameter("particle_width", StringConverter::toString(width - 0.1f));
		}
	} 

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_N))
	{
		for (size_t i = 1; i <= 3; ++i)
		{
			system = m_OgreEngine.m_pCurrentSceneManager->getParticleSystem("CSceneBlanchePluie" + StringConverter::toString(i));
			Real height = StringConverter::parseReal(system->getParameter("particle_height"));
			system->setParameter("particle_height", StringConverter::toString(height - 0.1f));
		}
	} 
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_A) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_BE_IncParticle, 0);
		m_pCameraFrameListener->mTimeUntilNextToggle = 3.0f;
	}
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_D) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_BE_IncPluie, 0);
		m_pCameraFrameListener->mTimeUntilNextToggle = 0.3f;
	}

	{
		Light *light = findLight(String("BlancheLight1"));
		if (NULL != light)
		{
			light->setPosition(m_pCurrentCamera->getPosition());
		}
	}

	return (true);
}

static GpuProgramParametersSharedPtr fpParams;

void CSceneBlanche :: notifyMaterialSetup(uint32 pass_id, MaterialPtr &mat)
{
	CSceneBase::notifyMaterialSetup(pass_id, mat);
    if(pass_id == 0)
    {
        //fpParams = mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
    }
}

void CSceneBlanche :: notifyMaterialRender(uint32 pass_id, MaterialPtr &material)
{
	CSceneBase::notifyMaterialRender(pass_id, material);

    if(pass_id == 0)
    {
		//Real value = m_Timer.getMilliseconds() / 100.0f;
		//value = value - Math::Floor(value);

		//fpParams->setNamedConstant("flicker", value);
	}
}

void CSceneBlanche :: processEvents(void)
{
	CSceneBase::processEvents();

	for (TEvents::iterator It = m_Events.begin(); It != m_Events.end(); ++It)
	{
		switch (It->m_Packet.eventid)
		{
			case SOpenMoveDisplayPacket::e_BE_SetLight:
			{
				Real val = std::max(0.0f, std::min(It->m_Packet.user_position_h, 1.0f));
				//Real val = Math::RangeRandom(0, 1);
				m_EndPoint = val;
				break;
			}
			case SOpenMoveDisplayPacket::e_BE_IncParticle:
			{
				if (m_Timer.getSeconds() > 30.0f && m_Timer.getSeconds() < 61.0f)
				{
					m_ParticleWidth = std::min(PARTICLE_WIDTH_MAX, m_ParticleWidth + (PARTICLE_WIDTH_MAX - 0.5f) / 10.0f);
					m_ParticleHeight = std::min(PARTICLE_HEIGHT_MAX, m_ParticleHeight + (PARTICLE_HEIGHT_MAX - 16.0f) / 10.0f);
				}
				break;
			}
			case SOpenMoveDisplayPacket::e_BE_IncPluie:
			{
				m_curPluie = std::min(m_curPluie + (m_MaxPluie / (m_resetParams.m_duration / 0.3f)), m_MaxPluie);

				m_ParticleWidth = std::min(m_ParticleWidth + (PARTICLE_WIDTH_MAX / (m_resetParams.m_duration / 0.3f)), PARTICLE_WIDTH_MAX);
				m_ParticleHeight = std::min(m_ParticleHeight + (PARTICLE_HEIGHT_MAX / (m_resetParams.m_duration / 0.3f)), PARTICLE_HEIGHT_MAX);
	
				break;
			}
			default:
			{
				break;
			}
		}
	}
}